home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’97 / Ventriloquist / source code / Beeper.INIT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-27  |  5.5 KB  |  205 lines  |  [TEXT/CWIE]

  1. #include <Events.h>
  2. #include <Resources.h>
  3. #include <Memory.h>
  4. #include <ToolUtils.h>
  5. #include <Gestalt.h>
  6. #include <Errors.h>
  7.  
  8. #include "Beeper.h"
  9.  
  10.     // some sane defaults in case we can't find our prefs.
  11. BeeperGlobals    gBeeperGlobs = {
  12.     0, 
  13.     0,
  14.     "\p",
  15.     "\p",
  16.     "\p",
  17.     "\p",
  18.     "\p"
  19. };
  20.  
  21. pascal short (*gOldSystemEvent)(EventRecord *theEvent);
  22.  
  23. pascal short BeeperSystemEvent(EventRecord *theEvent);
  24.  
  25. enum {
  26.     uppSystemEventProcInfo = kPascalStackBased | RESULT_SIZE(kTwoByteCode) | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  27. };
  28.  
  29. SelectorFunctionUPP        ourGestaltUPP;
  30.  
  31. static pascal OSErr BeeperGestalt(OSType selector, long *_response);
  32.  
  33. #ifdef powerc
  34.     // for Metrowerks' linker, this defines the interface for main().
  35.     ProcInfoType __procinfo = kCStackBased | RESULT_SIZE(kNoByteCode);
  36. #endif
  37.  
  38. void main(void)
  39. {
  40.     long                oldA4;
  41.     THz                    oldZone;
  42. //    BeeperGlobals        **bgh;
  43.     UniversalProcPtr    newSystemEventAddress;
  44.  
  45.         // Set up A4, so we can access our globals.
  46.     oldA4 = SetCurrentA4();
  47.  
  48.         // Set the current zone to the system zone.  In the 680x0 case, this
  49.         // is not necessary, but it's not a bad idea and it keeps us out of
  50.         // trouble when traps that we don't expect to have side effects
  51.         // unexpectedlty allocate memory from the current zone.  One example
  52.         // of this is the NewRoutineDescriptor routine.
  53.     oldZone = GetZone();
  54.     SetZone(SystemZone());
  55.  
  56.         // OK, we're relying on gestalt, so we have to be sure that it's
  57.         // implemented.  We do this by checking to see that Gestalt's trap
  58.         // address is different from the address of unimplemented traps.
  59.     if (GetOSTrapAddress(kGestaltTrapNumber) == UnimplementedTrapAddress) goto initFailed;
  60.  
  61.     ourGestaltUPP = NewSelectorFunctionProc(BeeperGestalt);
  62.     if (ourGestaltUPP == 0) goto initFailed;
  63.  
  64.     newSystemEventAddress = NewRoutineDescriptor((ProcPtr) &BeeperSystemEvent,uppSystemEventProcInfo,GetCurrentISA());
  65.     if (newSystemEventAddress == 0) goto initFailed;
  66.  
  67.         // now install our gestalt selector, which sets up a mechanism for our control panel
  68.         // to talk to us and at the same time makes sure we're not loading twice.
  69.     if (NewGestalt(kDTS_Signature, ourGestaltUPP) != noErr) goto initFailed;
  70.  
  71.         // At this point, we have tested for any failure conditions, and nothing has gone wrong.
  72.         // So now is the time to detach our code, patch our traps, and settle in.
  73.     DetachResource(GetResource('INIT', -4048));
  74.  
  75.         // Remember the old implementation of SystemEvent.
  76.     gOldSystemEvent = (void *) GetToolTrapAddress(kSystemEventTrapNumber);
  77.  
  78.         // Patch ourselves in.
  79.     SetToolTrapAddress(newSystemEventAddress, kSystemEventTrapNumber);
  80.  
  81. //    bgh = (BeeperGlobals **)Get1Resource('pref', -4048);
  82. //    if (bgh != 0 && GetHandleSize((Handle)bgh) == sizeof(gBeeperGlobs)) {
  83. //        gBeeperGlobs = **bgh;
  84. //    }
  85.  
  86. initFailed:
  87.         // Restore the old zone again
  88.     SetZone(oldZone);
  89.  
  90.         // And restore the value of A4 on the way out.
  91.     SetA4(oldA4);
  92. }
  93.  
  94. static pascal OSErr BeeperGestalt(OSType selector, long *response) {
  95.     long    oldA4;
  96.     OSErr    err = noErr;
  97.  
  98.         // Set up A4, so we can access our globals.
  99.     oldA4 = SetCurrentA4();
  100.  
  101.     switch (selector) {
  102.         case kGestaltGetInitGlobals:
  103.             *response = (long)&gBeeperGlobs;
  104.             break;
  105.         case kDTS_Signature:
  106.             *response = (long)ourGestaltUPP;
  107.             break;
  108.         case gestaltVersion:
  109.             *response = 0x0100;    // version 1.0 Gestalt interface for Beeper.
  110.             break;
  111.         default:
  112.             err = gestaltUnknownErr;
  113.             break;
  114.     }
  115.  
  116.         // Restore the value of A4 on the way out.
  117.     SetA4(oldA4);
  118.     return err;
  119. }
  120.  
  121. static void HandleKeyDown(short modifiers, long eventMessage);
  122.  
  123. pascal short BeeperSystemEvent(EventRecord *theEvent)
  124. {
  125.         // Set up A4, so we can access our globals.
  126.     long    oldA4;
  127.     short    result;
  128.  
  129.     oldA4 = SetCurrentA4();
  130.  
  131.         // Check for keyDown events, and pass them to HandleKeyDown:
  132.     if (theEvent->what == keyDown) {
  133.         HandleKeyDown(theEvent->modifiers, theEvent->message);
  134.     }
  135.  
  136.         // Call the old SystemEvent:
  137. #ifndef powerc
  138.     result = gOldSystemEvent(theEvent);
  139. #else
  140.     result = CallUniversalProc((UniversalProcPtr)gOldSystemEvent, uppSystemEventProcInfo, theEvent);
  141. #endif
  142.         // And restore the value of A4 on the way out.
  143.     SetA4(oldA4);
  144.  
  145.     return result;
  146. }
  147.  
  148. enum { kMaxKeysRecorded = sizeof(gBeeperGlobs.asBuf[0]) };
  149.  
  150. uchar    gLastKeys[kMaxKeysRecorded + 1];
  151.  
  152. static void HandleKeyDown(short modifiers, long eventMessage)
  153. {
  154.     StringPtr    lastkeys;    // we keep the address of gLastKeys in a local variable ...
  155.     
  156.     lastkeys = gLastKeys;    // ... because we access it so often
  157.  
  158.         // If the user types command-O or command-V, or command-Anything,
  159.         // our buffer is probably invalid, and we certainly shouldn't
  160.         // record the keystroke!
  161.     if (modifiers & cmdKey) {
  162. //        lastkeys[0] = 0;
  163.         return;
  164.     }
  165.  
  166.         // if it's a backspace, back up over one of our recorded keys.
  167.     if ('\b' == (char)eventMessage) {
  168.         if (lastkeys[0] != 0) {
  169.             lastkeys[0]--;
  170.         }
  171.         return;
  172.     }
  173.  
  174.         // if it isn't, add the new key to the end of what we've recorded so far.
  175.         // first, if we're about to overflow, throw away one old key.
  176.     if (lastkeys[0] == kMaxKeysRecorded) {
  177.         BlockMove(&lastkeys[2], &lastkeys[1], kMaxKeysRecorded - 1);
  178.         lastkeys[0]--;
  179.     }
  180.  
  181.         // then, store the new typed character:
  182.     if (' ' == (char)eventMessage)
  183.     {
  184.         BlockMove(&lastkeys[0],&gBeeperGlobs.asBuf[gBeeperGlobs.lWriteBuf][0],lastkeys[0]+1);
  185.         lastkeys[0] = 0;
  186.         gBeeperGlobs.lWriteBuf++;
  187.         if(gBeeperGlobs.lWriteBuf>4) gBeeperGlobs.lWriteBuf = 0;
  188.  
  189.     }
  190.     else
  191.     {
  192.         lastkeys[0]++;
  193.         lastkeys[lastkeys[0]] = eventMessage;
  194.     }
  195.  
  196.         // have we accumulated "beep"?
  197. //    if (lastkeys[0] == gBeeperGlobs.BeepString[0]) {
  198. //        if (RelString(lastkeys, gBeeperGlobs.BeepString, false /* not case sens */, true /* diacritical sensitive */) == sortsEqual) {
  199. //            SysBeep(8);
  200. //            lastkeys[0] = 0;
  201. //        }
  202. //    }
  203. }
  204.  
  205.